﻿#ifndef SANDBOX_2
#define SANDBOX_2

#include <cstring>
#include <fstream>
/*!-------此处请根据实际内存大小自行调整！-------!*/
#if __linux__
#define MAX_MEM 0x60000000
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#define MAX_MEM 0xb000000
#endif
/*!-------此处请根据实际内存大小自行调整！-------!*/

// Flag Value define
#define RUNNING 1
#define DEBUG 2
#define ERROR 4
#define TRIGGER (1 << 4)
#define ENABLE (1 << 5)
#define AVX (1 << 12)
#define DBUS_BUSY (1 << 13)
#define IO_BUSY (1 << 14)
#define PROTECTED (1 << 15)

typedef unsigned long long qword;
typedef unsigned int dword;
typedef unsigned short word;
typedef unsigned char byte;
typedef float real4;
typedef double real8;

enum ADDR_REG
{
	Code,
	Data,
	Stack,
	Base,
	SI,
	DI,
	EI1,
	EI2
};
enum SPEC_REG
{
	Flag,
	Timer,
	IDTR,
	Count,
	LDTR,
	TSSR,
	Page,
	Debug
};
enum DIRECTION
{
	IN_RAM,
	OUT_RAM
};
enum DTYPE
{
	BYTE = 1,
	WORD = 2,
	DWORD = 4,
	QWORD = 8,
	REAL4 = 4,
	REAL8 = 8
};
enum IOTYPE
{
	CHAR,
	SHORT,
	INT,
	LONG,
	SINGLE,
	DOUBLE
};
enum VTYPE
{
	I8,
	I16,
	I32,
	I64,
	F4,
	F8
};

union Vector
{
	byte bvalues[64];
	word wvalues[32];
	dword dvalues[16];
	qword qvalues[8];
	real4 r4values[16];
	real8 r8values[8];
};

static std::fstream disk;
static real4 fregs[8];
static real8 dregs[8];
static qword func_regs[8];
static qword addr_regs[8];
static qword special_regs[8];
static Vector vregs[16];
static byte ram[MAX_MEM];

template <class T>
T swapEndian(T value)
{
	T result = T(0);
	byte *_src = (byte *)&value;
	byte *_res = (byte *)&result;
	for (int i = 0; i < sizeof(T); i++)
		*(_res + i) = *(_src + sizeof(T) - i - 1);
	return result;
}
bool check_address(qword address)
{
	if (Flag & PROTECTED)
		return address < MAX_MEM ? true : false;
	else
		return address < 0x10000 ? true : false;
}
void ram_rw(DIRECTION dir, qword address, byte reg_var, DTYPE type)
{
	// Move reg value to memory
	// For function reg only,others regs unable to select data type
	if (!check_address(address))
	{
		// TODO:Throw Error:Address Error
	}
	if (dir == IN_RAM)
	{
		qword temp = swapEndian(func_regs[reg_var]);
		for (int i = 0; i < type; i++)
			*(ram + address + i) = *((byte *)&temp + 8 - type + i);
	}
	if (dir == OUT_RAM)
	{
		switch (type)
		{
		case BYTE:
			func_regs[reg_var] = *(ram + address);
			break;
		case WORD:
			strncpy((char *)(func_regs + reg_var), (char *)(ram + address), 2);
			func_regs[reg_var] = swapEndian(func_regs[reg_var]) >> 48;
			break;
		case DWORD:
			strncpy((char *)(func_regs + reg_var), (char *)(ram + address), 4);
			func_regs[reg_var] = swapEndian(func_regs[reg_var]) >> 32;
			break;
		case QWORD:
			strncpy((char *)(func_regs + reg_var), (char *)(ram + address), 8);
			func_regs[reg_var] = swapEndian(func_regs[reg_var]);
			break;
		}
	}
}
void flt_rw(DIRECTION dir, qword address, byte flt_reg, DTYPE type)
{
	if (!check_address(address))
	{
		// TODO:Throw Error:Address Error
	}
	if (dir == IN_RAM)
	{
		if (type & REAL4)
			strncpy((char *)(fregs + flt_reg), (char *)(ram + address), 4);
		else if (type & REAL8)
			strncpy((char *)(dregs + flt_reg), (char *)(ram + address), 8);
	}
	else
	{
		if (type & REAL4)
			strncpy((char *)(ram + address), (char *)(fregs + flt_reg), 4);
		else if (type & REAL8)
			strncpy((char *)(ram + address), (char *)(dregs + flt_reg), 8);
	}
}
void mount() { disk.open("hdd.bin", std::ios::binary); }
void umount() { disk.close(); }
void file_rw(DIRECTION dir)
{
	if (!disk.is_open())
	{
		// TODO:Throw Error:Hard Disk Not Found
	}
	if (dir == OUT_RAM)
	{
		disk.seekp(addr_regs[DI]);
		disk.write((char *)(ram + addr_regs[SI]), special_regs[Count] * 512);
	}
	else
	{
		disk.seekg(addr_regs[SI]);
		disk.read((char *)(ram + (addr_regs[DI])), special_regs[Count] * 512);
	}
}

#endif // !SANDBOX_2
